# -*- coding: utf-8 -*-
import types
#此模块暂不使用
class FsmError(Exception):
    pass
  
class Fsm(object):
    def __init__(self,context):
        self.__context=context
        self.__atomStates=[]
         
        self.__root=State('root',None,context,self)
        self.__start=self.__root['start']
        self.__end=self.__root['end']
        self.__state=self.__start
        
         
    def root(self):
        return self.__root
    
    def _asAtomState(self,state):
        state is not None and self.__atomStates.append(state)
    
    def _isAtomState(self,state):
        return state in self.__atomStates
    
    def init(self,state):
        if not state._isAtomState():
            raise FsmError,str(state)+"不能作为初始状态,因为它不是原子状态"
        self._asAtomState(state)
        self.transitState(state)
        
    def state(self):
        return self.__state
    
    def transitState(self,newState):
        oldState=self.__state
        oldState._exit(newState)
        self.__state=newState
        newState._entry(oldState)

interceptors={}
class State(object):
    def __init__(self,name,parent,context,fsm):
        self.__name=name
        self.__parent=parent
        self.__context=context
        self.__fsm=fsm
        
        self.__children={}
        self.__transitons={}
        self.__entryAction =None
        self.__exitAction =None

        if parent is None :
            self.__stateChain=(self,)
        else:
            self.__stateChain=parent.__stateChain+(self,)
        
    #override
    def __repr__(self):
        return self.__name
    
    #override
    def __getitem__(self,childName):
        if self.__fsm._isAtomState(self):
            raise FsmError,"已经作为转换目标状态的(%s)只能保持原子状态,它不能再增加子状态" % (self.__name)
        
        if not self.__children.has_key(childName):
            self.__children[childName]=State(childName,self,self.__context,self.__fsm)
        return self.__children[childName]

    def add(self,event,toState,action):
        """装配期使用"""
        if event is None :
            raise FsmError,"事件不能为None"
        if toState is not None and not toState._isAtomState():
            raise FsmError,str(toState)+"不能作为转换目标,因为它不是原子状态"
        
        self.__fsm._asAtomState(toState)
        eventName=self.__intercept(event)
         
        self.__transitons[eventName]=_Transition(toState,action,self.__fsm)
        
    def setEntryAction(self,action):
        """装配期使用"""
        self.__entryAction=action
        
    def setExitAction(self,action): 
        """装配期使用"""
        self.__exitAction=action
        

    def path(self):
        return "/"+"/".join(map(lambda x:x.name(),self.__stateChain) )
    
    def name(self):
        return self.__name

    def _isAtomState(self):
        return len(self.__children)==0

    def _entry(self,fromOldState):
        if self.__parent not in fromOldState.__stateChain:
            self.__parent._entry(fromOldState)
        self.__entryAction and self.__entryAction()
          
    def _exit(self,toNewState):
        self.__exitAction and self.__exitAction()
        if self.__parent not in toNewState.__stateChain:
            self.__parent._exit(toNewState)
    

    def __intercept(self,event):
        if(not self.__isIntercepted(event)):
            #if not self.__isInstanceMethodInContext(event):
            if not hasattr(self.__context,event.__name__):
                raise FsmError,"事件("+event.__name__+")必须是Context对象的方法"
            result=event.__name__
            interceptor=self.__getInterceptor(result)
            interceptors[interceptor]=result
            setattr(self.__context,result,interceptor)
            return result
        else:
            return interceptors[event]
    
    def __isIntercepted(self,event):
        return event.__name__=="__fsm_internal_interceptor"
    
    def __isInstanceMethodInContext(self,method):
        if not isinstance(method,types.MethodType):
            return False
        if method.im_class != type(self.__context):
            return False
        return True
    
    def __getInterceptor(self, eventName ):
        def __fsm_internal_interceptor( *args, **keywordArgs ):
            beforeDoEventState=self.__fsm.state()

            for s in beforeDoEventState.__stateChain:
                isStateChanged = beforeDoEventState != self.__fsm.state()
                if isStateChanged:
                    return 
                if s.__transitons.has_key(eventName):
                    
                    s.__transitons[eventName].doTran(*args, **keywordArgs )
                
        return __fsm_internal_interceptor     
    
class _Transition(object):
    def __init__(self,toState,action,fsm):
        self.__toState=toState
        self.__action=action
        self.__fsm=fsm
    #override
    def __repr__(self):
        actionName=self.__action and self.__action.__name__
        return "<Transition to='%s' action='%s'/>" % (str(self.__toState),actionName)
    
    def doTran(self,*args,**keywordArgs):
        self.__toState and self.__fsm.transitState(self.__toState)
        self.__action and self.__action(*args,**keywordArgs)
